package service

import (
	"gitee.com/sdynasty/clever/peer"
	"fmt"
	"reflect"
	"strings"
	"time"
)

type ReflectPerformer struct {

}

func (p *ReflectPerformer) OnClosed(sess *peer.Session) {

}

func (p *ReflectPerformer) OnReceive(sess *peer.Session, data []byte) error {
	t1 := time.Now()
	_, msgPack, err := routerCodec.Unmarshal(data)
	if err != nil {
		return fmt.Errorf("OnReceive routerCodec.Unmarshal error: %v", err)
	}
	router, ok := msgPack.Router.(string)
	if !ok {
		return fmt.Errorf("onreceive: invalid router:%v", msgPack.Router)
	}
	routerArr := strings.Split(router, ".")
	if len(routerArr) != 2 {
		return fmt.Errorf("onreceive: invalid router:%s", msgPack.Router)
	}
	serverName := routerArr[0]
	methodName := routerArr[1]

	s, ok := serviceList[serverName]
	if !ok {
		return fmt.Errorf("onreceive: function not registed router:%s err:%v", msgPack.Router, err)
	}
	h, ok := s.Handlers[methodName]
	if !ok {
		return fmt.Errorf("onreceive: function not registed router:%s err:%v", msgPack.Router, err)
	}
	var args = []reflect.Value{h.Receiver, reflect.ValueOf(sess), reflect.ValueOf(msgPack.DataPtr)}
	ack, err := p.callHandler(h.Method, args)
	if err != nil && ack != nil {
		rb, err := routerCodec.Marshal(router, ack, nil)
		if err != nil {
			return fmt.Errorf("routerCodec.Marshal: %v", err)
		}
		err = sess.Conn.Send(rb)
		if err != nil {
			return fmt.Errorf("performer Conn.Send: %v", err)
		}
	}

	fmt.Printf("performer onRecive take:%v\n", time.Since(t1))
	return nil
}

/**
 * 执行router方法
 */
func (p *ReflectPerformer) callHandler(foo reflect.Method, args []reflect.Value) (retValue interface{}, retErr error) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(fmt.Sprintf("callHandlerFunc: %v", err))
			//fmt.Println(utils.CallStack())
			retValue = nil
			retErr = fmt.Errorf("callHandlerFunc: call method pkg:%s method:%s err:%v", foo.PkgPath, foo.Name, err)
		}
	}()

	if ret := foo.Func.Call(args); len(ret) == 2 {
		retValue = ret[0].Interface()
		if r1 := ret[1].Interface(); r1 != nil {
			retErr = r1.(error)
		}
		return
	} else {
		return nil, fmt.Errorf("callHandlerFunc: call method pkg:%s method:%s", foo.PkgPath, foo.Name)
	}
}